package net.caidingke.shepherd.security;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.caidingke.shepherd.domain.user.User;
import net.caidingke.shepherd.exception.BusinessException;
import net.caidingke.shepherd.exception.ErrorCode;
import net.caidingke.shepherd.service.UserService;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author bowen
 */
@Component("userDetailsService")
@AllArgsConstructor
@Slf4j
public class CustomUserDetailsServiceImpl implements UserDetailsService {

    private final UserService userService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserDetails loadUserByUsername(final String login) {
        String lowercaseLogin = login.toLowerCase(Locale.ENGLISH);
        Optional<User> userFromDatabase = userService.findByUsername(lowercaseLogin);
        return userFromDatabase.map(user -> {
            if (!user.isEnabled()) {
                throw new BusinessException(ErrorCode.ACCOUNT_NOT_ACTIVITY);
            }
            List<GrantedAuthority> grantedAuthorities = userService
                    .getUserRoles(user.getId())
                    .stream()
                    .map(authority -> new SimpleGrantedAuthority(authority.getName()))
                    .collect(Collectors.toList());
            return new org.springframework.security.core.userdetails.User(
                    lowercaseLogin, user.getPassword(), grantedAuthorities);
        }).orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the " + "database"));
    }
}
